using System.Configuration;
using System.Xml;
using System.Collections.Generic;
using System.IO;
using System.Xml.Schema;
using System.Text;

namespace Gl.SettingsManager.Providers.ConfigurationSections
{
	internal class SettingsSection : ConfigurationSection
	{
		private List<SettingsCollection> _settings = new List<SettingsCollection>();

		public SettingsCollection GetCollection(string typeName, string contextName)
		{
			foreach (SettingsCollection coll in _settings)
				if (coll.TypeName == typeName && coll.ContextName == contextName)
					return coll;

			return null;
		}

		public void AddSettings(SettingsCollection collection)
		{
			_settings.Add(collection);
		}

		public void Clear()
		{
			_settings.Clear();
		}

		protected override void DeserializeSection(XmlReader reader)
		{
			XmlDocument doc = new XmlDocument();
			doc.Schemas.Add(string.Empty, XmlReader.Create(new MemoryStream(Resource.SettingsSection)));
			doc.Load(reader);
			doc.Validate(ValidationHandler);

			foreach (XmlNode settingsNode in doc.SelectNodes(SettingsSectionXml.SettingsCollection.XPath)){
				string typeName = settingsNode.Attributes[SettingsSectionXml.SettingsCollection.TypeName].Value;
				string contextName = settingsNode.Attributes[SettingsSectionXml.SettingsCollection.Context] == null ?
					string.Empty : settingsNode.Attributes[SettingsSectionXml.SettingsCollection.Context].Value;

				SettingsCollection collection = new SettingsCollection(typeName, contextName);
				_settings.Add(collection);

				foreach (XmlNode setting in 
					settingsNode.SelectNodes(SettingsSectionXml.SettingsCollection.Setting.Tag))
				{
					string name = setting.Attributes[SettingsSectionXml.SettingsCollection.Setting.Name].Value;
					string value = setting.InnerText;
					collection.Add(name, value);
				}
			}
		}

		protected override string SerializeSection(ConfigurationElement parentElement,
			string name, ConfigurationSaveMode saveMode)
		{
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;
			settings.NewLineOnAttributes = true;
			settings.IndentChars = "    ";
			settings.OmitXmlDeclaration = true;

			StringBuilder output = new StringBuilder();
			XmlWriter writer = XmlWriter.Create(output, settings);

			writer.WriteStartElement(SettingsSectionXml.SettingsSectionName);
			foreach (SettingsCollection settingsCollection in _settings)
			{
				writer.WriteStartElement(SettingsSectionXml.SettingsCollection.Tag);
				writer.WriteAttributeString(SettingsSectionXml.SettingsCollection.TypeName, settingsCollection.TypeName);
				if (!string.IsNullOrEmpty(settingsCollection.ContextName))
					writer.WriteAttributeString(SettingsSectionXml.SettingsCollection.Context, settingsCollection.ContextName);

				foreach (Setting setting in settingsCollection)
				{
					writer.WriteStartElement(SettingsSectionXml.SettingsCollection.Setting.Tag);
					writer.WriteAttributeString(SettingsSectionXml.SettingsCollection.Setting.Name, setting.Name);
					writer.WriteValue(setting.Value);
					writer.WriteEndElement();
				}
				writer.WriteEndElement();
			}
			writer.WriteEndElement();

			writer.Flush();

			return output.ToString();
		}

		private void ValidationHandler(object sender, ValidationEventArgs e)
		{
			throw new SettingsException(e.Exception, Exceptions.ConfigurationFileValidationFailed, e.Message);
		}
	}
}
